package com.runa.rccprotocol.analysis;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.comm.dto.newComm.AffiliatePanelVO;
import com.runa.monitor.comm.dto.newComm.HotMeterVO;
import com.runa.monitor.comm.dto.newComm.PanelVO;
import com.runa.monitor.comm.dto.newComm.ValveVO;
import com.runa.persistence.DateUtil;
import com.runa.persistence.config.CommConfig;
import com.runa.persistence.task.RequestPendingTask;
import com.runa.persistence.task.TaskTypeEnum;
import com.runa.persistence.util.LogUtil;
import com.runa.protocol.analysis.MetaBufferAnalysis;
import com.runa.protocol.analysis.ShellBufferAnalysis;
import com.runa.protocol.dto.DtuReport;
import com.runa.protocol.dto.IInterData;
import com.runa.protocol.enums.ByteOrder;
import com.runa.protocol.util.ByteUtil;
import com.runa.protocol.util.DigitalUtil;
import com.runa.rccprotocol.analysis.daiao.DaiAoAnalysis;
import com.runa.rccprotocol.analysis.pusai.PsAnalysis;
import com.runa.rccprotocol.analysis.tiger.TigerAnalysis;
import com.runa.rccprotocol.analysis.wukexing.WkxAnalysis;
import com.runa.rccprotocol.dto.ConcentratorElectric;
import com.runa.rccprotocol.dto.equdata.ConcenReportData;
import com.runa.rccprotocol.dto.equdata.HeatMeterData;
import com.runa.rccprotocol.dto.equdata.TerminalCalendarClock;
import com.runa.rccprotocol.dto.runa.RunaConcenAffirmDeny;
import com.runa.rccprotocol.dto.runa.RunaConcenResponseData;
import com.runa.rccprotocol.dto.tiangang.TianGangFmuDataAck;
import com.runa.rccprotocol.dto.tiger.TigerValveRequestData;
import com.runa.rccprotocol.dto.wukexing.WkxValveRequestData;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author diandian
 * @Date 2021/12/10 10:06
 */
@Slf4j
public class TianGangAnalysis extends ShellBufferAnalysis<byte[]> {
    public TianGangAnalysis(MetaBufferAnalysis analysis) {
        super(analysis, 0);
    }

    Logger logger = LoggerFactory.getLogger(getClass());

    DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");

    @Override
    public int fill(byte[] data, int length, String n) {
        interData = null;
        this.netEquNo = n;
        log.debug("天罡: {} {}", n, ByteUtil.byteToHexString(data, 0, length));
//        LogService.saveErrorLog("天罡", "TIANGANG", data, length);


        TaskTypeEnum taskType = RequestPendingTask.getTaskType(netEquNo);
        if (null != taskType) {
            switch (taskType) {
                case READ_TIGER_VALVE:
                    TigerAnalysis tigerAnalysis = new TigerAnalysis();
                    tigerAnalysis.handle(data, 0, length);
                    break;
            }
        }

        for (int i = 0; i < length; i++) {
            if ((data[i] & 0xff) == 0x68 && data[i+1] == data[i+2] && (data[i+3] & 0xff) == 0x68) {
                int l = data[i + 1] & 0xff;
                if (i + 4 + l + 2 > length) {
                    return -1;
                }
                if (!(data[i + 4 + l] == ByteUtil.sum(data, i + 4, l))) {
                    break;
                }
                if (null != taskType) {
                    if (taskType == TaskTypeEnum.READ_DA_METER) {
                        DaiAoAnalysis daiAoAnalysis = new DaiAoAnalysis();
                        int i1 = daiAoAnalysis.handleMeter(data, i, length);
                        interData = daiAoAnalysis.getInterData();
                        return i1;
                    }
                }
            }
        }

        //首先判断是否是188协议表
//        if (Hex)
        if (data[0] == 0x68 || (data[0] & 0xff) == 0xFE) {
            for (int i = 0; i < length; i++) {
                if (data[i] == (byte) 0xFE) continue;
                if (data[i] == (byte) 0x68) {
                    if ((data[i + 1] & 0xff) == 0x25) {
                        handleMeterData(data, i, i + 1, length);
                    } else if ((data[i + 1] & 0xff) == 0x81) {
                        return runaValveHandle(data, i, length);
                    } else if (RequestPendingTask.isKtValve(netEquNo)) {
                        return ktValveHandle(data, i, length);
                    } else if (RequestPendingTask.isPsValve(netEquNo)) {
                        PsAnalysis psAnalysis = new PsAnalysis();
                        int i1 = psAnalysis.valveHandle(data, i, length);
                        interData = psAnalysis.getInterData();
                        return i1;
                    }
                } else {
                    break;
                }
            }
        }
//        for (int i = 0; i < data.length; i++) {
//            int start = data[i] & 0xff;
//            if (start == 0x68) {
//                begin = i;
//                break;
//            }
//        }

        if (data[1] == 3 && data[2] == 0x46) {
            ValveVO valveVO = modbusValveData(data);
            RunaConcenResponseData runaConcenResponseData = new RunaConcenResponseData();
            runaConcenResponseData.addRepData(valveVO);
            this.interData = runaConcenResponseData;
            return 0;
        }

        if (data[1] == 16 && DigitalUtil.calcCrc16(data, 6) == ByteUtil.byteToUShort(data, 6, ByteOrder.BA)) {
            RunaConcenAffirmDeny affirmDeny = new RunaConcenAffirmDeny(true);
            affirmDeny.setAddress(netEquNo);
            this.interData = affirmDeny;
            return 0;
        }

        //判断是否是modbus读操作
        if (0x03 == data[1]) {
            handleModbusMeterData(data, length);
            return 0;
        }

        if (length == 1 && 0xE5 == (data[0] & 0xff)) {
            interData = new RunaConcenAffirmDeny(true);
            return 0;
        }

        //如果连数据域的长度都不满足
        if (length < 6) {
            return -1;
        }
        int begin;
        boolean fmu = false;
        for (begin = 0; begin < length; begin++) {
            if ((data[begin] & 0xff) == 0xF8) {
                if ((data[begin + 1] & 0xff) == 0x00) {
                    fmu = true;
                    break;
                }
            }
        }
        if (fmu) {
            int len = data[begin + 3] & 0xff;
            if ((begin + 4 + len + 2) > length) {
                return -1;
            }
            if (!(ByteUtil.sum(data, begin, 4 + len) == data[begin + 4 + len])) {
                return 0;
            }
            return hanleFmuData(data, begin, length);
        }

        //电表电量
        boolean el = false;
        boolean equ = false;
        boolean val = false;
        int dataLength = 0;
        for (int i = 0; i < length; i++) {
            if ((data[i] & 0xff) == 0x68) {
                if ((data[i + 3] & 0xff) == 0x68) {
                    dataLength = data[i + 1] & 0xff;
                    begin = i;
                    equ = true;
                    break;
                }
                if ((data[i + 7] & 0xff) == 0x68) {
                    el = true;
                    begin = i;
                    break;
                }
                if ((data[i + 1] & 0xff) == 0x80) {
                    val = true;
                    begin = i;
                    break;
                }
            }
        }

        if (val) {
            WkxAnalysis wkxAnalysis = new WkxAnalysis();
            int i = wkxAnalysis.handleWkxValve(data, begin, length);
            this.interData = wkxAnalysis.getInterData();
            return i;
        }

        if (el) {
            return electric(data, begin, length);
        }

        if (!equ) {
            //判断是否是188协议海威茨表
            for (int i = 0; i < data.length; i++) {
                int start = data[i] & 0xff;
                if (start == 0x68) {
                    begin = i;
                    break;
                }
            }
            //校验
            int dataLen = data[begin + 10] & 0xff;
            byte check = data[begin + 11 + dataLen];
            byte sum = ByteUtil.sum(data, begin, 11 + dataLen);
            if (check != sum) {
                return 0;
            }
            int index = begin;
            ++index;
            int equType = data[index] & 0xff;
            if (equType == 0x20) {
                handleMeterData(data, begin, index, length);
            }
            return 0;
        }

        //数据长度判断
        if (length < dataLength + 4 + 2) {
            return -1;
        }

        int index = begin;
        index += 4;
        int ctr = data[index] & 0xff;

        if (ctr != 0x08) {
            return 0;
        }

        index += 2;
        int ci = data[index] & 0xff;
        if (ci == 0x72) {
            ++index;
            String serial = ByteUtil.byteToHexStringFlip(data, index, 4);

            index += 4;
            String factory = ByteUtil.byteToHexStringFlip(data, index, 2);

            index += 2;
            //05有线，06无线
            int equComType = data[index] & 0xff;

            ++index;
            int equType = data[index] & 0xff;
            switch (equType) {
                case 0x21:
                    if (data[105] != 0x16) {
                        return 0;
                    }
                    //cs校验
                    byte checkCs = ByteUtil.sum(data, begin + 4, 100);
                    byte cs = data[104];
                    if (checkCs != cs) {
                        return 0;
                    }
                    if (equComType == 5 || equComType == 6) {
                        return valveData(serial, data, begin, index, length);
                    }
                case 0x04:
                    if (data[length - 1] != 0x16) {
                        return 0;
                    }
                    //cs校验
                    byte checkCsOfMeter = ByteUtil.sum(data, begin + 4, data[begin + 2]);
                    byte csOfMeter = data[length - 2];
                    if (checkCsOfMeter != csOfMeter) {
                        return 0;
                    }
//                    if (equComType == 5 || equComType == 6) {
                    return meterData(serial, data, begin, index, length);
//                    }

            }
        } else if (ci == 0x78) {
            //控制阀门响应
            ++index;
            byte dif = data[index];
            ++index;
            byte vif = data[index];
            if (dif == 0x0C && vif == 0x79) {
                //cs
                byte check = ByteUtil.sum(data, 4, 12);
                if (check != data[16]) {
                    return length - begin - 18;
                }

                //二级地址
                ++index;
                //响应报文
                index += 4;
                String string = ByteUtil.byteToHexString(data, index, 3);
                if (string.equals("0F4C50")) {
                    interData = new RunaConcenAffirmDeny(null, true);
                } else {
                    interData = new RunaConcenAffirmDeny(null, false);
                }
                return length - begin - 18;
            }
        }
        return 0;
    }

    public ValveVO modbusValveData(byte[] data) {
        ValveVO valveData = new ValveVO();
        valveData.setReadTime(new Date());
        valveData.setIndex(data[0] & 0xff);
        valveData.setRemoteSet((float) ByteUtil.byteToShort(data, 3, ByteOrder.AB));
        valveData.setActOpen((float) ByteUtil.byteToShort(data, 7, ByteOrder.AB));
        valveData.setSoftVersion(String.valueOf(ByteUtil.byteToShort(data, 17, ByteOrder.AB)));
        valveData.setSupplyTemp(ByteUtil.byteToFloat(data, 21, ByteOrder.CDAB));
        valveData.setReturnTemp(ByteUtil.byteToFloat(data, 25, ByteOrder.CDAB));
        valveData.setEnvTemp(ByteUtil.byteToFloat(data, 29, ByteOrder.CDAB));
        valveData.setSupplyPre(ByteUtil.byteToFloat(data, 33, ByteOrder.CDAB) / 1000);
        valveData.setBehindPre(ByteUtil.byteToFloat(data, 37, ByteOrder.CDAB) / 1000);
        valveData.setFrontPre(ByteUtil.byteToFloat(data, 41, ByteOrder.CDAB) / 1000);
        int statusCode = ByteUtil.byteToShort(data, 65, ByteOrder.AB) & 0xffff;
        valveData.setLR(ByteUtil.byteToShort(data, 67, ByteOrder.AB) == 1 ? ValveVO.LREnum.远程 : ValveVO.LREnum.本地);
        int model = ByteUtil.byteToShort(data, 69, ByteOrder.AB);
        switch (model) {
            case 1:
                valveData.setModel(ValveVO.ModelEnum.开度);
                break;
            case 2:
                valveData.setModel(ValveVO.ModelEnum.室温);
                break;
            case 3:
                valveData.setModel(ValveVO.ModelEnum.流速);
                break;
            case 4:
                valveData.setModel(ValveVO.ModelEnum.供回温差);
                break;
            case 5:
                valveData.setModel(ValveVO.ModelEnum.回温);
                break;
            case 6:
                valveData.setModel(ValveVO.ModelEnum.供温);
                break;
        }
        valveData.setStatus(Integer.toHexString(statusCode));
//        StringBuilder faults = new StringBuilder();
        ArrayList<String> list = new ArrayList<>();
        if ((statusCode >> 8 & 1) == 1) {
            list.add("进水故障");
//            faults.append("进水故障,");
        }
        if ((statusCode >> 9 & 1) == 1) {
            list.add("回水故障");
//            faults.append("回水故障");
        }
        valveData.setFaultCode(list);
        return valveData;
    }

    @SneakyThrows
    private int handleModbusMeterData(byte[] data, int len) {
        int index = 0;
//        int serial = data[index] & 0xff;
//        String serialNo = String.valueOf(serial);
//        int length = serialNo.length();
//        StringBuilder serialNoBuf = new StringBuilder(serialNo);
//        for (int i = 0; i < 14 - length; i++) {
//            serialNoBuf.insert(0, "0");
//        }
//
        HeatMeterData meterData = new HeatMeterData();
//        meterData.setSerial(serialNoBuf.toString());

        index += 2;
        int dataLen = data[index] & 0xff;
        int surplus = len - (dataLen + 5);
        if (surplus < 0) {
            return -1;
        }
        ++index;

        //校验
        int checkValue = DigitalUtil.calcCrc16(data, 0, dataLen + 3);
        Integer value = ByteUtil.byteToUShort(data, dataLen + 3, ByteOrder.BA);
        if (checkValue != value) {
            return surplus;
        }
        index += 4;

        double acch = ByteUtil.byteToInt(data, index, ByteOrder.ABCD) * 10;
        meterData.setAccHeat((float) acch);
        index += 4;
        double heat = ByteUtil.byteToInt(data, index, ByteOrder.ABCD) * 0.01;
        meterData.setPower((float) heat);
        index += 4;
        double flow = ByteUtil.byteToInt(data, index, ByteOrder.ABCD) * 0.00001;
        meterData.setInstantFlow((float) flow);
        index += 4;
        double accFlow = ByteUtil.byteToInt(data, index, ByteOrder.ABCD);
        meterData.setAccFlow((float) accFlow);
        index += 4;
        double inte = ByteUtil.byteToShort(data, index, ByteOrder.AB) * 0.01;
        meterData.setInTemperature((float) inte);
        index += 2;
        double re = ByteUtil.byteToShort(data, index, ByteOrder.AB) * 0.01;
        meterData.setOutTemperature((float) re);
        index += 2;
        int workTime = ByteUtil.byteToInt(data, index, ByteOrder.ABCD);
        meterData.setWorkTime(workTime);
        index += 4;
//        String timeS = ByteUtil.bcd2str(data, index, 12, false);
        Short year = ByteUtil.byteToShort(data, index, ByteOrder.AB);
        index += 2;
        Short mo = ByteUtil.byteToShort(data, index, ByteOrder.AB);
        index += 2;
        Short day = ByteUtil.byteToShort(data, index, ByteOrder.AB);
        index += 2;
        Short shi = ByteUtil.byteToShort(data, index, ByteOrder.AB);
        index += 2;
        Short fen = ByteUtil.byteToShort(data, index, ByteOrder.AB);
        index += 2;
        Short miao = ByteUtil.byteToShort(data, index, ByteOrder.AB);
        index += 2;
        Calendar instance = Calendar.getInstance();
        instance.set(year, mo, day, shi, fen, miao);
        index += 12;
        meterData.setMeterDate(TerminalCalendarClock.getInstance(instance.getTime()));
        meterData.setMeterStatus(heatMeterFaultsOfModbus(ByteUtil.byteToHexString(data, index, 2)));

        RunaConcenResponseData runaConcenResponseData = new RunaConcenResponseData();
        runaConcenResponseData.addRepData(meterData);
        this.interData = runaConcenResponseData;
        return surplus;
    }

    private static String heatMeterFaultsOfModbus(String status) {
        int hexCode = Integer.parseInt(status, 16);
        StringBuilder faults = new StringBuilder();
        if ((hexCode >> 10 & 1) == 1) {
            faults.append("电池欠压,");
        }
//        if ((hexCode >> 2 & 1) == 1) {
//            faults.append("进水回水故障,");
//        }
//        if ((hexCode >> 1 & 1) == 1) {
//            faults.append("温度异常,");
//        }
        return faults.toString();
    }

    private int meterData(String serial, byte[] data, int begin, int index, int length) {
        HotMeterVO meterData = new HotMeterVO();
        meterData.setMeterSerial(serial);
        index++;

        index++;
//        meterData.setMeterStatus(ByteUtil.bcd2str(data, index, 1, true));
        meterData.setStatus(ByteUtil.byteToHexString(data[index]));
        index++;
        index += 2;

        //热量
        meterData.setAccHeat((float) ByteUtil.bcdToInt(data, index + 2, 4, false));
        index += 6;
        //正向流量
        meterData.setAccFlow((float) (ByteUtil.bcdToInt(data, index + 3, 4, false) * 0.1));
        index += 7;
        //反向流量
//        meterData.setAccHeat(ByteUtil.bcdToInt(data, index+2, 4, false));
        index += 7;
        //进水温度
        meterData.setSupplyTemp((float) (ByteUtil.bcdToInt(data, index + 2, 3, false) * 0.01));
        index += 5;
        //回水温度
        meterData.setReturnTemp((float) (ByteUtil.bcdToInt(data, index + 2, 3, false) * 0.01));
        index += 5;
        //功率
        meterData.setPower((float) (ByteUtil.bcdToInt(data, index + 2, 4, false) * 0.1));
        index += 6;
        //瞬时流量
        meterData.setFlow((float) (ByteUtil.bcdToInt(data, index + 2, 4, false) * 0.001));
        index += 6;
        //工作时间
        index += 6;
        //故障时间
        index += 6;
        //线路板加电时间
        index += 6;
        meterData.setReadDate(new Date());
        RunaConcenResponseData responseData = new RunaConcenResponseData();
        responseData.addRepData(meterData);
        interData = responseData;
        return 0;
    }

    private int hanleFmuData(byte[] data, int begin, int length) {
        int cmd = data[begin + 2] & 0xff;
        //电量解析
        switch (cmd) {
            case 0x00:
                return registerData(data, length, begin);
            case 0x01:
                return heartBeatData(data, length, begin, false);
            case 0x02:
                return heartBeatData(data, length, begin, true);
            case 0x06: //处理成功应答指令
                interData = new RunaConcenAffirmDeny(true);
                return 0;
            case 0x07: //处理错误应答指令
                interData = new RunaConcenAffirmDeny(false);
                return 0;
            case 0x09:
                int rs = analysis.fill(data, length, netEquNo);
                interData = analysis.gain();
                return rs;
            case 0x13:
                //解析电量
                String electricValue = new String(data, 5, 12).replace("ElecEnergy=", "");
                ConcentratorElectric electric = new ConcentratorElectric(netEquNo);
                ConcenReportData reportData = new ConcenReportData();
                reportData.setElectric(new Float(electricValue) / 1000);
                reportData.setTime(new Date());
                reportData.setDate(new Date());
                electric.setReportData(reportData);
                interData = electric;
                return 0;
            case 0x20:
                analysis.fill(data, length, netEquNo);
                interData = analysis.gain();
                return 0;
        }
        return 0;
    }

    private int electric(byte[] data, int start, int size) {
        if (netEquNo == null) {
            return 0;
        }
        if (size - start - 20 < 0) {
            return -1;
        }
        if ((data[start + 19] & 0xff) != 0x16) {
            return 0;
        }
        //        68 95 62 07 16 08 21 68 91 08 33 33 33 33 45 33 33 33 50 16
        int index = start;
        ++index;
        String serial = ByteUtil.byteToHexStringFlip(data, index, 6);
        //cs校验
        boolean csResult = data[start + 18] == ByteUtil.sum(data, start, 18);
        if (!csResult) {
            return 0;
        }

        byte[] el = new byte[4];

        for (int i = 14 + start; i < 18 + start; i++) {
            int datum = (data[i] & 0xff) - 0x33;
            el[i - (14 + start)] = (byte) datum;
        }

        double electricValue = ByteUtil.bcdToInt(el, 0, 4, false) * 0.01;

        ConcentratorElectric electric = new ConcentratorElectric(netEquNo);
        ConcenReportData reportData = new ConcenReportData();
        reportData.setTime(new Date());
        reportData.setDate(new Date());
        reportData.setElectric((float) electricValue);
        electric.setReportData(reportData);
        interData = electric;
        return size - (start + 20);
    }


    private int heartBeatData(byte[] data, int length, int begin, boolean needAck) {
        String[] serialArray = new String[1];
        int result = getSerialNo(data, length, begin, serialArray);
        if (result != 0) {
            return result;
        }
        LogUtil.linkDetect(serialArray[0], "天罡", data, length, "心跳");
        netEquNo = serialArray[0];
        interData = new DtuReport(serialArray[0]);
        if (needAck) {
            ((DtuReport) interData).setMustAck(true);
            byte[] ackBytes = Arrays.copyOf(data, length);
            int l = data[3];
            ackBytes[1] = 0x01;
            ackBytes[l + 4] = ByteUtil.sum(ackBytes, 0, l + 4);
            ((DtuReport) interData).setAck(new TianGangFmuDataAck(ackBytes, serialArray[0]));
        }
        return result;
    }

    private int registerData(byte[] data, int length, int begin) {
        String[] serialArray = new String[1];
        int result = getSerialNo(data, length, begin, serialArray);
        if (result < 0) {
            return result;
        }
        netEquNo = serialArray[0];
        LogUtil.linkDetect(netEquNo, "天罡", data, length, "登录");
        DtuReport dtuReport = new DtuReport(netEquNo);
        dtuReport.setMustAck(true);

        String dateStr = this.format.format(new Date());
        byte[] bytes = ByteUtil.hexStringToByte(dateStr);

        byte[] ackBytes = new byte[]{(byte) 0xF8, 0x01, 0x10, 0x07, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], 0, 0x16};
        ackBytes[11] = ByteUtil.sum(ackBytes, 0, 11);
//        String s = ByteUtil.byteToHexString(ackBytes);
//        System.out.println(s);
        dtuReport.setAck(new TianGangFmuDataAck(ackBytes, netEquNo));
        this.interData = dtuReport;
        return result;
    }

    private int getSerialNo(byte[] data, int length, int begin, String[] serialArray) {
        int index = begin;
        index += 3;
        int len = data[index] & 0xff;

        int needLen = begin + 4 + len + 2;
        if (length < needLen) {
            return -1;
        }

        //cs校验
        byte cs = data[index + len + 1];
        byte sum = ByteUtil.sum(data, begin, begin + 4 + len);
        if (cs != sum) {
            return length - needLen;
        }

        int end = data[index + len + 2] & 0xff;
        if (0x16 != end) {
            return 0;
        }

        ++index;
        String serial = ByteUtil.byteToHexString(data, index, 4);
        serialArray[0] = serial;
        return length - needLen;
    }

    private int valveData(String serial, byte[] data, int begin, int index, int length) {
        int accessNo = data[++index] & 0xff;
        int status = data[++index] & 0xff;

        ++index;
        int sig = ByteUtil.bcdToInt(data, index, 2, true);

        index += 2;
        int factoryData = data[index] & 0xff;

        ++index;
        String protocolVersion = String.valueOf(ByteUtil.bcdToInt(data, index, 2, true) * 0.01);

        index += 2;
        Integer valveOpen = data[index] & 0xff;

        //口径
        ++index;

        //报警 00h见表1.2.1.1.6（工作模式，温度异常，温控器开关阀，用户报警）
        ++index;

        //温控器设定温度，当前温度
        ++index;

        //温控器设定温度为21℃
        ++index;
        int settingTem = data[index] & 0xff;

        //当前温度123.4℃（如果为FFFF，则表示阀门没有获取到温控器的温度）
        ++index;
        double panelTem = ByteUtil.bcdToInt(data, index, 2, false) * 0.1;

        index += 2;
        //温控器当前温度所对应的时间21日03点51分
        String panelTime = ByteUtil.byteToHexStringFlip(data, index, 3);

        //如果为FFh，不解析，否则为阀门状态（解析见表1.2.1.1.10）
        index += 3;

        //供暖相关，见表1.2.1.1.2。出厂/供暖/锁定/余额/欠费
        ++index;

        //阀门状态，表1.2.1.1.3。开关命令/执行命令/电机状态/总线带电/无线模块电源
        ++index;
        int tes = data[index] & 0xff;


        //阀门运行状态。见表1.2.1.1.4.
        ++index;
        byte openByte = data[index];

        //电机电源电压4.9V
        ++index;

        //门限电压3.2V
        ++index;

        //保留
        ++index;

        //当前时间2013年4月20日14点31分15秒
        ++index;
        String timeStr = ByteUtil.byteToHexStringFlip(data, index, 7);

        //保留  当前开阀时长12345678分钟
        index += 7;
        String tem1 = ByteUtil.byteToHexString(data, index, 4);

        //保留 最近一次0:00记录的开阀时长12345678分钟
        index += 4;
        String tem2 = ByteUtil.byteToHexString(data, index, 4);

        //0表示开度控制，1表示通断控制。
        index += 4;
        int valveType = data[index] & 0xff;

        //温控器控制阀门开度范围为10%---50%。
        ++index;
        String valveOpenRange = ByteUtil.byteToHexString(data, index, 2);

        //控器控制阀门开阀时，全关的阀门开启的开度为32%。
        index += 2;
        int tem3 = data[index] & 0xff;

        //保留 识别码为03/04时：阀门点动的基本步长为10（十六进制） 识别码为05/06时不解析
        ++index;

        //保留 识别码为05/06时，当前开度67.8%。
        ++index;
//        double valveOpen = ByteUtil.bcdToInt(data, index, 2,false)*0.1;

        // 识别码为05/06时:第1字节不解析，第2字节表示回水温度修正值（解析方法见表1.2.1.1）。后2字节表示回水温度23.4℃，为00h 80h表示为负温度
        index += 4;
        //第一个字节不解析
        int correct = data[index];
        //第二个字节表示回水温度修正值
        ++index;
        //后2字节表示回水温度23.4℃，为00h 80h表示为负温度
        ++index;
        double returnTem = ByteUtil.bcdToInt(data, index, 2, false) * 0.1;

        //阀门生产码12345678
        index += 2;
        String productionCode = ByteUtil.byteToHexStringFlip(data, index, 4);

        //保留
        index += 4;

        //阀门硬件版本
        ++index;
        int hardwareVersion = ByteUtil.bcdToInt(data, index, 2, false);

        //保留
        index += 2;
        String tem5 = ByteUtil.bcd2str(data, index, 2, true);

        //温控器(硬件版本1234/软件4556)
        index += 2;
        String panelVersion = ByteUtil.bcd2str(data, index, 4, false);

//        无线产品：无线地址12345678。
//        有线产品：不解析（根据第13位的设备识别码判断有线还是无线）
        index += 4;
        String wirelessAddress = ByteUtil.bcd2str(data, index, 4, false);

        //保留
        index += 4;
        String tem6 = ByteUtil.bcd2str(data, index, 2, false);

        //保留
        ++index;

        //阀门电池电压3.6V
        ++index;

        //保留
        ++index;
        int tem7 = ByteUtil.bcdToInt(data, index, 4, false);

        //阀门开关次数12345678次
        index += 4;
        int valveCount = ByteUtil.bcdToInt(data, index, 4, false);

        //自动开关间隔1234分钟
        index += 4;
        int valveOpenCloseTime = ByteUtil.bcdToInt(data, index, 2, false);

        //保留
        index += 2;

        //温控器电池电压3.0V
        ++index;

        //保留
        ++index;
        int tem8 = ByteUtil.bcdToInt(data, index, 2, false);

        //温控器控温范围6℃---28℃
        index += 2;
        int panelTemRange = ByteUtil.bcdToInt(data, index, 2, false);


        ValveVO valveVO = new ValveVO();
//        ValveData valveData = new ValveData();
//        valveVO.setValveLockTarget(Float.valueOf(tem3));
        valveVO.setValveSerial(serial);
        valveVO.setReturnTemp((float) returnTem);
        valveVO.setActOpen((float) valveOpen);
        valveVO.setOpenTime((float) valveOpenCloseTime);
//        valveVO.setSetTemperature(settingTem);
        valveVO.setSoftVersion(String.valueOf(hardwareVersion));
        boolean switchState = valveOpen != 0;
//        valveData.setSwitchState(switchState);
//        short zero = 0;
//        valveData.setPanel0(newComm ValveData.Panel(0, 0, (float) panelTem, zero));
//        valveData.setFaults("");
        RunaConcenResponseData responseData = new RunaConcenResponseData();
        responseData.addRepData(valveVO);
        this.interData = responseData;
        return length - begin - 106;
    }

    private int ktValveHandle(byte[] data, int begin, int length) {
        if (length < begin + 11) {
            return -1;
        }
        byte c = data[begin + 9];
        switch (c) {
            case (byte)0x81:
                return ktReadValveResponse(data, begin, length);
            case (byte)0xA5:
                if ((data[begin + 11 + 12] != ByteUtil.sum(data, begin, 11 + 12))) {
                    return 0;
                }
                this.interData = new RunaConcenAffirmDeny(true);
                break;
        }
        return 0;
    }

    private int runaValveHandle(byte[] data, int begin, int length) {
        if (length < begin + 11) {
            return -1;
        }
        int len = data[begin + 10];
        if (length < begin + 11 + len + 2) {
            return -1;
        }
        if ((data[begin + 11 + len] != ByteUtil.sum(data, begin, 11 + len))) {
            return 0;
        }
        byte c = data[begin + 9];
        switch (c) {
            case (byte)0x81:
                runaReadValveResponse(data, begin, length);
                break;
            case (byte)0x84:
                this.interData = new RunaConcenAffirmDeny(true);
                break;
            case (byte)0xC4:
                this.interData = new RunaConcenAffirmDeny(false);
                break;
        }

        return 0;
    }

    private int ktReadValveResponse(byte[] data, int begin, int length) {
        int len = data[begin + 10];
        if (length < begin + 11 + len + 2) {
            return -1;
        }
        if ((data[begin + 11 + len] != ByteUtil.sum(data, begin, 11 + len))) {
            return 0;
        }
        ValveVO valveVO = new ValveVO();
        valveVO.setValveSerial(ByteUtil.byteToHexString(data, begin+1, 1) + ByteUtil.byteToHexString(data, begin+4, 5));
        int index = begin + 14;
        valveVO.setOpenTime((float)ByteUtil.byteToInt(data, index, ByteOrder.DCBA));
        index += 4;
        byte b1 = data[index++];
        byte b2 = data[index++];
        if ((b1 & 1) == 1) {
            // 管道温度1
            index += 2;
        }
        if ((b1 >> 1 & 1) == 1) {
            // 管道温度2
            index += 2;
        }
        if ((b1 >> 2 & 1) == 1) {
            // 管道压力1
            index += 2;
        }
        if ((b1 >> 3 & 1) == 1) {
            // 管道压力2
            index += 2;
        }
        if ((b2 & 1) == 1) {
            // 模块电压
            index += 1;
        }
        Date parse;
        try {
            parse = new SimpleDateFormat("yyMMddHHmmss").parse(ByteUtil.byteToHexString(data, index, 6));
            valveVO.setValveDate(parse);
        } catch (ParseException e) {

        }
        index += 6;
        valveVO.setStatus(ByteUtil.byteToHexString(data, index, 2));
        byte v1 = data[index++];
        byte v2 = data[index++];
        if (v1 == 0xCC) {
            valveVO.setActOpen(100f);
        } else if (v1 == 0xDD) {
            valveVO.setActOpen(0f);
        } else {
            valveVO.setActOpen((float)v1);
        }
        List<String> faultList = new ArrayList<>();
        if ((v2 >> 1 & 1) == 1 || (v2 >> 2 & 1) == 1) {
            faultList.add("温度异常");
        }
        if ((v2 >> 3 & 1) == 1) {
            faultList.add("阀门异常");
        }
        valveVO.setFaultCode(faultList);

        RunaConcenResponseData runaConcenResponseData = new RunaConcenResponseData();
        runaConcenResponseData.addRepData(valveVO);
        this.interData = runaConcenResponseData;
        return 0;
    }

    private void runaReadValveResponse(byte[] data, int begin, int length) {
        ValveVO valveVO = new ValveVO();

        int index = begin;
        String serial = ByteUtil.bcd2str(data, index + 2, 4, false);
        valveVO.setValveSerial(serial);
        index = index + 11 + 3;
        index = index + 4 + 2 + 4 + 6 + 4 + 1*2 + 5 + 1*7 + 2 + 4 + 1*8 + 8 + 2*2;

        Date parse;
        try {
            parse = format.parse(ByteUtil.bcd2str(data, index, 7, false));
            valveVO.setValveDate(parse);
        } catch (ParseException e) {

        }
        index += 7;
        valveVO.setStatus(ByteUtil.byteToHexString(data, index, 2));
        byte s1 = data[index++];
        byte s2 = data[index++];
        if ((s1 >> 2 & 1) == 1) {
            valveVO.setActOpen((float)data[index++]);
        } else {
            if ((s1 & 3) == 0) {
                valveVO.setActOpen(100f);
            } else if ((s1 & 3) == 1) {
                valveVO.setActOpen(0f);
            }
        }
        List<String> faultList = new ArrayList<>();
        if ((s1 >> 6 & 1) == 1) {
            faultList.add("阀体分离");
        }
        if ((s1 >> 7 & 1) == 1) {
            faultList.add("无线异常");
        }
        valveVO.setFaultCode(faultList);
        index = index + 4 + 8;

        try {
            AffiliatePanelVO panelVO = new AffiliatePanelVO();
            panelVO.setReadTime(new Date());
            // 平均温度
            index += 2;

            // 当前温度
            String s = ByteUtil.byteToHexStringFlip(data, index, 2);
            panelVO.setTemperature(Float.parseFloat(s.substring(0, 3)) / 10);
            index += 2;

            // 设定温度
            index += 2;

            // 电池电压
            float f = (float)(((data[index] & 0xff) >> 4) + 21) / 10;
            panelVO.setBatteryVol(f);
            index += 1;

            // 面板状态字
            panelVO.setStatus(ByteUtil.byteToHexString(data, 0, 1));
            List<String> panelFaults = new ArrayList<>();
            if ((data[index] & 1) == 1) {
                panelFaults.add("电池欠压");
            }
            panelVO.setFaultCode(panelFaults);

            valveVO.setPanelVOList(Collections.singletonList(panelVO));
        } catch (Exception e) {
            log.error("", e);
        }

        RunaConcenResponseData runaConcenResponseData = new RunaConcenResponseData();
        runaConcenResponseData.addRepData(valveVO);
        this.interData = runaConcenResponseData;
    }

    private void handleMeterData(byte[] data, int begin, int index, int len) {
        HotMeterVO meterData = new HotMeterVO();
        ++index;
        String addresss = ByteUtil.bcd2str(data, begin + 2, 4, false);
        meterData.setMeterSerial(addresss);
        index += 7;

        int ctrCode = data[index] & 0xff;
        ++index;

        //数据域长度
        ++index;

        //数据标识DI，序号SER，序列号，
        index += 3;

        //结算日热量
        double dayHeat = ByteUtil.bcdToInt(data, index, 4, false) * 0.01;
        //单位，占一个字节
        index += 5;

        //当前热量
//        meterData.setAccHeat((float) (ByteUtil.bcdToInt(data, index, 4, false) * 0.01));
//        index += 5;
//
//        //热功率
//        meterData.setPower((float) (ByteUtil.bcdToInt(data, index, 4, false) * 0.0001));
//        index += 5;
//
//        //流量
//        meterData.setFlow((float) (ByteUtil.bcdToInt(data, index, 4, false) * 0.00001));
//        index += 5;
//
//        //累积流量
//        meterData.setAccFlow((float) (ByteUtil.bcdToInt(data, index, 4, false) * 0.01));
//        index += 5;
//
//        //供水温度
//        meterData.setSupplyTemp((float) (ByteUtil.bcdToInt(data, index, 3, false) * 0.01));
//        index += 3;
//
//        //回水温度
//        meterData.setReturnTemp((float) (ByteUtil.bcdToInt(data, index, 3, false) * 0.01));
//        index += 3;
//
//        //累积工作时间
//        meterData.setWorkTime((ByteUtil.bcdToInt(data, index, 3, false)));


        float accHeat = (float) (Integer.parseInt(ByteUtil.byteToHexStringFlip(data, index, 4)) * 0.01);
        index += 4;
        meterData.setAccHeat(RunaDeviceAnalysis.toKwh(accHeat, data[index++] & 0xff));
        float power = (float) (Integer.parseInt(ByteUtil.byteToHexStringFlip(data, index, 4)) * 0.01);
        index += 4;
        meterData.setPower(RunaDeviceAnalysis.toKw(power, data[index++] & 0xff));
        float flow = (float) (Integer.parseInt(ByteUtil.byteToHexStringFlip(data, index, 4)) * 0.0001);
        index += 4;
        meterData.setFlow(RunaDeviceAnalysis.toM3h(flow, data[index++] & 0xff));
        float accFlow = (float) (Integer.parseInt(ByteUtil.byteToHexStringFlip(data, index, 4)) * 0.01);
        index += 4;
        meterData.setAccFlow(RunaDeviceAnalysis.toM3(accFlow, data[index++]));
        meterData.setSupplyTemp((float) (Integer.parseInt(ByteUtil.byteToHexStringFlip(data, index, 3)) * 0.01));
        index += 3;
        meterData.setReturnTemp((float) (Integer.parseInt(ByteUtil.byteToHexStringFlip(data, index, 3)) * 0.01));
        index += 3;
        meterData.setWorkTime(Integer.parseInt(ByteUtil.byteToHexStringFlip(data, index, 3)));


        index += 3;

        //实时时间
        Date parse;
        try {
//            if ("TIANGGNG".equalsIgnoreCase(model)){
//                parse = format.parse(ByteUtil.bcd2str(data, index, 4, false));
//            }else {
//                Date parse = format.parse(ByteUtil.byteToHexString(data, index, 7));
            parse = format.parse(ByteUtil.bcd2str(data, index, 7, false));
//            }

            meterData.setMeterDate(parse);
        } catch (ParseException e) {

        }
        index += 7;
        meterData.setStatus(ByteUtil.byteToHexString(data, index, 2));
        meterData.setFaultCode(heatMeterFaults(ByteUtil.byteToHexString(data, index, 2)));

        RunaConcenResponseData runaConcenResponseData = new RunaConcenResponseData();
        runaConcenResponseData.addRepData(meterData);

        if ("太原".equals(CommConfig.getProjectAddress()) && null != this.netEquNo) {
            runaConcenResponseData.setAddress(this.netEquNo);
        }
        this.interData = runaConcenResponseData;

    }

    static List heatMeterFaults(String hexCode) {
        int hexCodeOne = Integer.parseInt(hexCode.substring(0, 2), 16);
        int hexCodeTwo = Integer.parseInt(hexCode.substring(2, 4), 16);
        ArrayList<String> list = new ArrayList<>();
        if ((hexCodeOne >> 4 & 1) == 1) {
            list.add("电池欠压");
        }
        if ((hexCodeOne >> 7 & 1) == 1) {
//            faults.append("EEPROM错误,");
            list.add("EEPROM错误");
        }
        if ((hexCodeOne & 1) == 1 || (hexCodeOne >> 1 & 1) == 1 || (hexCodeOne >> 2 & 1) == 1 || (hexCodeOne >> 3 & 1) == 1) {
//            faults.append("通道空管,");
            list.add("通道空管");
        }
        if ((hexCodeTwo & 1) == 1 || (hexCodeOne >> 1 & 1) == 1 || (hexCodeOne >> 2 & 1) == 1 || (hexCodeOne >> 3 & 1) == 1) {
//            faults.append("温度故障,");
            list.add("温度故障");
        }
        if ((hexCodeTwo >> 4 & 1) == 1 || (hexCodeOne >> 6 & 1) == 1 || (hexCodeOne >> 7 & 1) == 1) {
//            faults.append("流量故障,");
            list.add("流量故障");
        }
        return list;
    }

    public static void main(String[] args) {
        String netSerial = "00821826";
        String s = "F8 00 00 0E 00 80 22 11 04 00 4C 00 00 00 00 00 28 00 31 16";
        s = "FEFEFE68810113302300111181651F90010000C841000015100104000000000000B4210000000001133023150000000064000000250005003500000000000000003C0100000A00000090998037172109070622208400640000000000001E0300000001000000000000B04000000000000000000016";
        s = "FEFEFE68810414302300111184031F9012BE16";
        RequestPendingTask.addTask(netSerial, new RequestPendingTask(TaskTypeEnum.READ_METER));
        s = "FFFFFFFF68805075400200785D8127901F01411100411100000000000000000000000048208900118813705106311221081A4081E4E43316";
        s = "FEFEFE68810113302300111181651F90120000C841000015100104000000000000C6390000000001133023150000000064000000250005003500000000000000003C0100000A00000090998038473915110622208400640000000000001E0300000001000000000000B04000000000000000009A16";
        s = "FEFEFEFEFEFEFEFEFEFEFEFEFE682525680137008F41812E1F90000000000005414113080570040000176006010035326124012C954100213800205302364801040325200000A116";
//        s = "FEFEFE68810113302300111181651F90120000C8410000151001040000000000009C390000000001133023150000000064000000250005003500000000000000003C0100000A00000090997038210015110622208400640000000000001E0300000001000000000000B04000000000000000000116";
//        RequestPendingTask.addTask(netSerial, new RequestPendingTask(TaskTypeEnum.READ_KT_VALVE));
//        s = "6810000001240706968116901FB09E2636000301EEEE43706B24022301331364022416";
//        RequestPendingTask.addTask(netSerial, new RequestPendingTask(TaskTypeEnum.WRITE_KT_VALVE));
//        s = "681000000124070696A505A017005A64000000000000005F16";
        TianGangAnalysis analysis = new TianGangAnalysis(null);
        byte[] bytes = ByteUtil.hexStringToByte(s);
        System.out.println(analysis.fill(bytes, bytes.length, netSerial));
        System.out.println(JSON.toJSONString(analysis.gain()));
    }

}
